package com.sunkyc.framework.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sunkyc.commons.contants.GlobContants;
import com.sunkyc.commons.exception.CustomerException;
import com.sunkyc.framework.system.CacheKey.AuthroticationCacheKeys;
import com.sunkyc.framework.system.CacheKey.SystemCacheKeys;
import com.sunkyc.framework.utils.RedisUtils;
import com.sunkyc.framework.system.entity.SysMenu;
import com.sunkyc.framework.system.entity.SysMenuAncestors;
import com.sunkyc.framework.system.mapper.SysMenuMapper;
import com.sunkyc.framework.system.service.SysMenuAncestorsService;
import com.sunkyc.framework.system.service.SysMenuService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 菜单权限表 服务实现类
 * </p>
 *
 * @author sunkyc
 * @since 2022-05-31
 */
@Service
@RequiredArgsConstructor
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {
    private final SysMenuMapper baseMapper;
    private final RedisUtils redisUtils;
    private final SysMenuAncestorsService menuAncestorsService;



    /**
     * 获取最顶层级的父类id
     */
    private Long minParentId(){
        return baseMapper.minParentId();
    }


    @Override
    public List<Tree<String>> treeList() {
        List<Tree<String>> list= redisUtils.getCacheList(SystemCacheKeys.MENU_TREE_MANAGER+"_list");
        if(CollectionUtil.isNotEmpty(list)) return list;

        List<SysMenu> sysMenus = baseMapper.selectList(Wrappers.lambdaQuery(SysMenu.class).orderByAsc(SysMenu::getOrderNum));
        TreeNodeConfig config = new TreeNodeConfig();
        // 设置排序字段
        config.setWeightKey("orderNum");
        // 设置主键
        config.setIdKey("menuId");
        // 设置深度，不设置无限树
        config.setDeep(5);
        list = TreeUtil.build(sysMenus, minParentId().toString(), config, (node, tree) -> {
            tree.setId(node.getMenuId().toString());
            tree.setName(node.getTitle());
            tree.setParentId(node.getParentId().toString());

            // 额外的值
            tree.put("title", node.getTitle());
            tree.put("menuType", node.getMenuType());
            tree.put("menuName", node.getMenuName());
            tree.put("orderNum", node.getOrderNum());
            tree.put("path", node.getPath());
            tree.put("component", node.getComponent());
            tree.put("isLink", node.getIsLink());
            tree.put("isIframe", node.getIsIframe());
            tree.put("link", node.getLink());
            tree.put("isHide", node.getIsHide());
            tree.put("isKeepAlive", node.getIsKeepAlive());
            tree.put("isAffix", node.getIsAffix());
            tree.put("icon", node.getIcon());
            tree.put("perms", node.getPerms());
            tree.put("createTime", node.getCreateTime());
        });
        if(CollectionUtil.isNotEmpty(list))
            redisUtils.setCacheList(SystemCacheKeys.MENU_TREE_MANAGER+"_list",list);
        return list;
    }

    @Override
    @Transactional
    public int addMenu(SysMenu sysMenu) {
        SysMenu menu = restMenu(sysMenu);
        int count =baseMapper.insert(menu);
        if(count>0){
            List<SysMenuAncestors> sysMenuAncestors = initAncestorsByMenu(menu);
            sysMenuAncestors.forEach(val -> menuAncestorsService.save(new SysMenuAncestors().setMenuId(menu.getMenuId()).setMenuAncestorId(val.getMenuAncestorId())));
            redisUtils.deleteByPrefix(SystemCacheKeys.MENU_TREE_MANAGER);
            redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
        }
        return count;
    }

    @Override
    @Transactional
    public int editMenu(SysMenu sysMenu) {
        if(menuAncestorsService.checkedIsChildren(sysMenu.getMenuId(),sysMenu.getParentId())){
            throw new CustomerException("别搞 SOA 操作！");
        }
        SysMenu dbMenu = baseMapper.selectById(sysMenu.getMenuId());
        if(!dbMenu.getParentId().equals(sysMenu.getParentId())){
            if(baseMapper.exists(Wrappers.lambdaQuery(SysMenu.class).eq(SysMenu::getParentId,sysMenu.getMenuId()))){
                throw new CustomerException("请先设置子菜单或者移除子菜单再进行操作");
            }
        }
        int count =baseMapper.updateById(sysMenu);
        if(count>0) {
            redisUtils.deleteByPrefix(SystemCacheKeys.MENU_TREE_MANAGER);
            redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
        }
        return count;
    }

    @Override
    public int delMenuById(Long menuId) {

        int count =baseMapper.deleteById(menuId);
        if(count>0){
            menuAncestorsService.deleByMenuId(menuId);
            redisUtils.deleteByPrefix(AuthroticationCacheKeys.AUTH_DATA_SCOPE_USER_ID_LIST);
            redisUtils.deleteByPrefix(SystemCacheKeys.MENU_TREE_MANAGER);
        }
        return count;
    }

    private List<SysMenuAncestors> initAncestorsByMenu(SysMenu sysMenu){
        List<SysMenuAncestors> sysMenuAncestors = menuAncestorsService.queryByMenuId(sysMenu.getParentId());
        if(CollectionUtil.isEmpty(sysMenuAncestors)){
            sysMenuAncestors=new ArrayList<>();
        }
        sysMenuAncestors.add(new SysMenuAncestors().setMenuId(sysMenu.getMenuId()).setMenuAncestorId(sysMenu.getParentId()));
        return sysMenuAncestors;
    }



    private SysMenu restMenu(SysMenu sysMenu){
        if(sysMenu.getMenuType().equals(GlobContants.MENU_TYPE_BUTTON)){
            SysMenu menu = new SysMenu();
            menu.setMenuType(sysMenu.getMenuType());
            menu.setTitle(sysMenu.getTitle());
            menu.setPerms(sysMenu.getPerms());
            menu.setParentId(sysMenu.getParentId());
            menu.setOrderNum(sysMenu.getOrderNum());
            return menu;
        }
        if(StrUtil.isBlank(sysMenu.getMenuName())){
            sysMenu.setMenuName(GlobContants.DEFAULT_MENU_NAME);
        }
        return sysMenu;
    }


}
